package dao

import (
	"errors"
	"go-gateway-learn/dto"
	"go-gateway-learn/golang_common/lib"
	"go-gateway-learn/middleware"
	"go-gateway-learn/public"
	"net/http/httptest"
	"strings"
	"sync"

	"github.com/gin-gonic/gin"
)

type ServiceDetail struct {
	Info          *ServiceInfo   `json:"info" description:"服务基本信息"`
	HTTPRule      *HttpRule      `json:"http_rule" description:"http_rule"`
	TCPRule       *TcpRule       `json:"tcp_rule" description:"tcp_rule"`
	GRPCRule      *GrpcRule      `json:"grpc_rule" description:"grpc_rule"`
	LoadBalance   *LoadBalance   `json:"load_balance" description:"load_balance"`
	AccessControl *AccessControl `json:"access_control" description:"access_control"`
}

type ServiceManager struct {
	ServiceMap   map[string]*ServiceDetail
	ServiceSlice []*ServiceDetail
	Locker       sync.RWMutex
	init         sync.Once
	err          error
}

var ServiceManagerHandler *ServiceManager

func NewServiceManager() *ServiceManager {
	return &ServiceManager{
		ServiceMap:   map[string]*ServiceDetail{},
		ServiceSlice: []*ServiceDetail{},
		Locker:       sync.RWMutex{},
		init:         sync.Once{},
		err:          nil,
	}
}

func init() {
	ServiceManagerHandler = NewServiceManager()
}

func (s *ServiceManager) HTTPAccessModel(c *gin.Context) (*ServiceDetail, error){
	host := c.Request.Host
	host = host[0:strings.Index(host,":")]
	path := c.Request.URL.Path
	for _, serviceItem := range s.ServiceSlice{
		if serviceItem.Info.LoadType != public.LoadTypeHTTP{
			continue
		}
		if serviceItem.HTTPRule.RuleType==public.HTTPRuleTypeDomain{
			if serviceItem.HTTPRule.Rule == host{
				return serviceItem,nil
			}
		}
		if serviceItem.HTTPRule.RuleType==public.HTTPRuleTypePrefixURL{
			if strings.HasPrefix(path,serviceItem.HTTPRule.Rule){
				return serviceItem,nil
			}
		}
	}
	return nil, errors.New("not matched service")
}

func (s *ServiceManager) LoadOnce() error{
	s.init.Do(func() { 
		serviceInfo := &ServiceInfo{}
		c,_ := gin.CreateTestContext(httptest.NewRecorder())
		db, err := lib.GetGormPool("default")
		if err != nil {
			middleware.ResponseError(c, 2000, err)
			return
		}
		param := &dto.ServiceListInput{PageNo:1, PageSize:9999}
		list, _, err := serviceInfo.PageList(c, db, param)
		if err != nil {
			middleware.ResponseError(c, 2001, err)
			return
		}
		s.Locker.Lock()
		defer s.Locker.Unlock()
		for _, listItem := range list{
			tmpListItem := listItem
			serviceDetail, err := tmpListItem.ServiceDetail(c, db, &tmpListItem)
			if err != nil{
				middleware.ResponseError(c, 2002, err)
				return
			}
			s.ServiceMap [listItem.ServiceName] = serviceDetail
			s.ServiceSlice= append(s.ServiceSlice, serviceDetail)
		}
	
	})
	return s.err
}

func (s *ServiceManager) GetTcpServiceList()[]*ServiceDetail{
	list := []*ServiceDetail{}
	for _, serverItem := range s.ServiceSlice{
		tempItem := serverItem
		if tempItem.Info.LoadType == public.LoadTypeTCP{
			list = append(list, tempItem)
		}
	}
	return list 
}